package com.hzncc.flowable_diboot.contract.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.Texts;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.diboot.core.binding.Binder;
import com.diboot.core.binding.QueryBuilder;
import com.diboot.core.holder.ThreadLocalHolder;
import com.diboot.core.service.DictionaryService;
import com.diboot.core.service.impl.BaseServiceImpl;
import com.diboot.core.util.BeanUtils;
import com.diboot.core.util.JSON;
import com.diboot.core.util.S;
import com.diboot.core.vo.JsonResult;
import com.diboot.core.vo.LabelValue;
import com.diboot.core.vo.Pagination;
import com.diboot.file.util.FileHelper;
import com.diboot.iam.entity.BaseLoginUser;
import com.diboot.iam.util.IamSecurityUtils;
import com.diboot.tenant.entity.IamTenant;
import com.diboot.tenant.service.IamTenantService;
import com.hzncc.flowable_diboot.contract.dto.ContractAuditDTO;
import com.hzncc.flowable_diboot.contract.entity.*;
import com.hzncc.flowable_diboot.contract.service.*;
import com.hzncc.flowable_diboot.contract.vo.*;
import com.hzncc.flowable_diboot.entity.SapCustomer;
import com.hzncc.flowable_diboot.enums.ContractAuditStatusEnum;
import com.hzncc.flowable_diboot.enums.ContractAuditTypeEnum;
import com.hzncc.flowable_diboot.enums.OAStatusEnum;
import com.hzncc.flowable_diboot.enums.SAPStatusEnum;
import com.hzncc.flowable_diboot.exception.BusinessException;
import com.hzncc.flowable_diboot.mapper.ContractAuditMapper;
import com.hzncc.flowable_diboot.project_contracts.entity.ProjectContractAudit;
import com.hzncc.flowable_diboot.project_contracts.mapper.ProjectContractAuditMapper;
import com.hzncc.flowable_diboot.service.SapCustomerService;
import com.hzncc.flowable_diboot.service.bpm.BpmProcessDefinitionService;
import com.hzncc.flowable_diboot.service.bpm.BpmProcessInstanceService;
import com.hzncc.flowable_diboot.service.bpm.BpmProcessTaskService;
import com.hzncc.flowable_diboot.service.impl.CommonService;
import com.hzncc.flowable_diboot.util.SapUtil;
import com.hzncc.flowable_diboot.util.WordUtils;
import com.hzncc.flowable_diboot.vo.bpm.BpmProcessInstanceCreateReqVO;
import com.hzncc.flowable_diboot.vo.bpm.BpmTaskReqVO;
import com.hzncc.flowable_diboot.vo.bpm.BpmTaskRespVO;
import com.sap.conn.jco.JCoException;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipOutputStream;


/**
 * 合同审批 相关Service实现类
 *
 * @author MyName
 * @version 1.0
 * @date 2024-07-12
 * Copyright © MyCorp
 */
@Log4j2
@Service
public class ContractAuditServiceImpl extends BaseServiceImpl<ContractAuditMapper, ContractAudit> implements ContractAuditService {

    @Resource
    private ContractAuditMapper contractAuditMapper;

    @Resource
    private ContractInfoService contractInfoService;

    @Resource
    private ContractExtService contractExtService;

    @Resource
    private ContractProductService contractProductService;

    @Resource
    private ContractProductMaterialService contractProductMaterialService;

    @Resource
    private ContractAuditUpdateService contractAuditUpdateService;

    @Resource
    private ContractAuditCancelService contractAuditCancelService;

    @Resource
    private BpmProcessDefinitionService bpmProcessDefinitionService;

    @Resource
    private BpmProcessInstanceService bpmProcessInstanceService;

    @Resource
    private BpmProcessTaskService bpmProcessTaskService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private KonpService konpService;

    @Autowired
    private SapCustomerService customerService;

    @Autowired
    private ContractTeamService contractTeamService;

    @Autowired
    private SalesContractService salesContractService;

    @Autowired
    private ProjectContractAuditMapper projectContractAuditMapper;

    @Autowired
    private FieldMappingService fieldMappingService;

    @Autowired
    private SapUtil sapUtil;

    @Autowired
    private IamTenantService iamTenantService;

    @Autowired
    private DictionaryService dictionaryService;

    @Override
    protected void afterCreate(ContractAudit entity) {
        createOrUpdateN2NRelations(ContractAuditUser::getContractAudit, entity.getId(), ContractAuditUser::getUser, entity.getStarUids());
    }

    @Override
    protected void afterUpdate(ContractAudit entity) {
        createOrUpdateN2NRelations(ContractAuditUser::getContractAudit, entity.getId(), ContractAuditUser::getUser, entity.getStarUids());
    }

    @Override
    public List<ContractAuditTaskVO> getContractTodo() {
        List<ContractAuditTaskVO> contractAuditTaskVOList = new ArrayList<>();
        List<BpmTaskRespVO> todoList = bpmProcessTaskService.getTodoList(new BpmTaskReqVO(), new Pagination());
        for (BpmTaskRespVO bpmTaskRespVO : todoList) {
            ContractAuditTaskVO contractAuditTaskVO = new ContractAuditTaskVO();
            String processInstanceId = bpmTaskRespVO.getProcessInstanceId();
            LambdaQueryWrapper<ContractAudit> auditQuery = new LambdaQueryWrapper<>();
            auditQuery.eq(ContractAudit::getInstanceId, processInstanceId).eq(ContractAudit::isDeleted, 0);
            ContractAudit singleEntity = this.getSingleEntity(auditQuery);
            ContractAuditVO contractAuditVO = this.getContractDetail(singleEntity.getId());
            contractAuditTaskVO.setTaskId(bpmTaskRespVO.getId()).setContractAuditVO(contractAuditVO);
            contractAuditTaskVOList.add(contractAuditTaskVO);
        }
        return contractAuditTaskVOList;
    }

    @Override
    @Transactional
    public void archiveContract(List<String> contractAuditIds) {
        //归档校验
        for (String contractAuditId : contractAuditIds) {
            canArchive(contractAuditId);
        }
        //SAP推送完成且回款金额与合同金额相同才可归档
        LambdaUpdateWrapper<ContractAudit> contractAuditLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        contractAuditLambdaUpdateWrapper.set(ContractAudit::getContractStatus, ContractAuditStatusEnum.ARCHIVED.getCode())
                .in(ContractAudit::getId, contractAuditIds).eq(ContractAudit::isDeleted, 0);
        this.update(contractAuditLambdaUpdateWrapper);
    }

    @Override
    public ContractAuditVO copyContractDetail(String contractAuditId) {
        ContractAuditVO contractAuditVO = this.getContractDetail(contractAuditId);
        ContractAuditVO clear = this.clear(contractAuditVO, true);
        // 修改审批时间、合同供应商和合同采购方签约时间
        clear.setAuditTime(LocalDateTime.now());
        if (clear.getContractExtVO() != null) {
            clear.getContractExtVO().setSupplierSignTime(LocalDateTime.now());
            clear.getContractExtVO().setBuyerSignTime(LocalDateTime.now());
        }
        clear.setContractOriginalRecoveryStatus("0");
        return clear;
    }

    @Override
    public ContractAuditVO getContractDetail(String contractAuditId) {
        //合同审批信息
        ContractAuditVO contractAuditVO = this.getViewObject(contractAuditId, ContractAuditVO.class);
        if (contractAuditVO.getContractProductVOList() == null) {
            contractAuditVO.setContractProductVOList(new ArrayList<>());
        }
        ContractAuditCancelListVO contractAuditCancelVO = contractAuditVO.getContractAuditCancelVO();
        if (contractAuditCancelVO != null) {
            contractAuditCancelVO.setCustomerId(contractAuditVO.getCustomerId());
            contractAuditCancelVO.setCustomerName(contractAuditVO.getCustomerName());
        }
        for (ContractProductListVO productListVO : contractAuditVO.getContractProductVOList()) {
            productListVO.setProductDesc(productListVO.getMachineType() == null ? StrUtil.nullToDefault(productListVO.getProductCode(), "") : productListVO.getMachineType() + " " + productListVO.getProductType());
        }
//        if (S.equals(contractAuditVO.getAuditType(), ContractAuditTypeEnum.UPDATE.getCode()) || S.equals(contractAuditVO.getContractStatus(), ContractAuditStatusEnum.HISTORY.getCode())) {
//            contractAuditVO.setDiffVOList(getDiff(contractAuditVO.getId()));
//            contractAuditVO.setProductDiffVOList(getProductDiff(contractAuditVO.getId()));
//        }
        return contractAuditVO;
    }

    @Override
    public ContractAuditVO getContractDetailByCode(String contractCode) {
        String contractAuditId = contractAuditMapper.selectLastVersionContract(contractCode);
        return this.getContractDetail(contractAuditId);
    }

    @Override
    public String getContractAuditIdByCode(String contractCode) {
        return contractAuditMapper.selectLastVersionContract(contractCode);
    }

    @Override
    public List<ContractAuditVO> getContractPage(ContractAuditPageReqVO contractAuditPageReqVO, Pagination pagination) {
        IPage<ContractAuditVO> page = new Page<>(pagination.getPageIndex(), pagination.getPageSize());
        //查询sap合同号
        if (ObjectUtils.isNotEmpty(contractAuditPageReqVO) && StringUtils.isNotEmpty(contractAuditPageReqVO.getSapContractCode())) {
            LambdaQueryWrapper<ContractProduct> contractProductLambdaQueryWrapper = new LambdaQueryWrapper<>();
            contractProductLambdaQueryWrapper.eq(ContractProduct::isDeleted, 0).like(ContractProduct::getSapContractCode, contractAuditPageReqVO.getSapContractCode());
            List<ContractProduct> contractProductList = contractProductService.getEntityList(contractProductLambdaQueryWrapper);
            List<String> contractCodeList = contractProductList.stream().map(ContractProduct::getContractCode).distinct().collect(Collectors.toList());
            contractAuditPageReqVO.setContractCodeList(contractCodeList);
        }
        //分页查询合同审批列表
        IPage<ContractAuditVO> pageResult = contractAuditMapper.selectContractList(page, contractAuditPageReqVO);
        List<ContractAuditVO> contractAuditVOList = pageResult.getRecords();
        contractAuditVOList = Binder.convertAndBindRelations(contractAuditVOList, ContractAuditVO.class);
        List<String> contractAuditIdList = contractAuditVOList.stream().map(ContractAuditVO::getId).collect(Collectors.toList());
        if (contractAuditIdList.isEmpty()) {
            return contractAuditVOList;
        }
        //查询合同基础信息
        LambdaQueryWrapper<ContractInfo> infoQuery = new LambdaQueryWrapper<>();
        infoQuery.eq(ContractInfo::isDeleted, 0).in(ContractInfo::getContractAuditId, contractAuditIdList);
        List<ContractInfo> contractInfoList = contractInfoService.getEntityList(infoQuery);
        List<ContractInfoListVO> contractInfoVOList = Binder.convertAndBindRelations(contractInfoList, ContractInfoListVO.class);
        Map<String, ContractInfoListVO> auditToInfoMap = contractInfoVOList.stream().collect(Collectors.groupingBy(ContractInfoListVO::getContractAuditId
                , Collectors.collectingAndThen(
                        Collectors.toList(), list -> list.stream().findFirst().orElse(null))));
        //查询合同扩展信息
        LambdaQueryWrapper<ContractExt> extQuery = new LambdaQueryWrapper<>();
        extQuery.eq(ContractExt::isDeleted, 0).in(ContractExt::getContractAuditId, contractAuditIdList);
        List<ContractExt> contractExtList = contractExtService.getEntityList(extQuery);
        List<ContractExtListVO> contractExtVOList = Binder.convertAndBindRelations(contractExtList, ContractExtListVO.class);
        Map<String, ContractExtListVO> auditToExtMap = contractExtVOList.stream().collect(Collectors.groupingBy(ContractExtListVO::getContractAuditId
                , Collectors.collectingAndThen(
                        Collectors.toList(), list -> list.stream().findFirst().orElse(null))));
        //查询合同产品信息
        LambdaQueryWrapper<ContractProduct> productQuery = new LambdaQueryWrapper<>();
        productQuery.eq(ContractProduct::isDeleted, 0).in(ContractProduct::getContractAuditId, contractAuditIdList);
        List<ContractProduct> contractProductList = contractProductService.getEntityList(productQuery);
        List<ContractProductListVO> contractProductVOList = Binder.convertAndBindRelations(contractProductList, ContractProductListVO.class);
        Map<String, List<ContractProductListVO>> auditToProductListMap = contractProductVOList.stream().collect(Collectors.groupingBy(ContractProductListVO::getContractAuditId));
        //查询当前版本合同产品物料信息
        List<String> productIdList = contractProductVOList.stream().map(ContractProductListVO::getId).collect(Collectors.toList());
        LambdaQueryWrapper<ContractProductMaterial> materialQuery = new LambdaQueryWrapper<>();
        materialQuery.eq(ContractProductMaterial::isDeleted, 0).in(ContractProductMaterial::getContractProductId, productIdList);
        List<ContractProductMaterial> contractProductMaterialList = contractProductMaterialService.getEntityList(materialQuery);
        List<ContractProductMaterialVO> contractProductMaterialVOList = Binder.convertAndBindRelations(contractProductMaterialList, ContractProductMaterialVO.class);
        Map<String, List<ContractProductMaterialVO>> productToMaterialMap = contractProductMaterialVOList.stream().collect(Collectors.groupingBy(ContractProductMaterialVO::getContractProductId));
        for (ContractProductListVO contractProductVO : contractProductVOList) {
            contractProductVO.setContractProductMaterialVOList(productToMaterialMap.get(contractProductVO.getId()));
        }
        //查询当前版本合同变更信息
        LambdaQueryWrapper<ContractAuditUpdate> updateQuery = new LambdaQueryWrapper<>();
        List<ContractAuditUpdate> contractAduitUpdateList = contractAuditUpdateService.getEntityList(updateQuery);
        List<ContractAuditUpdateListVO> contractAuditUpdateVOList = Binder.convertAndBindRelations(contractAduitUpdateList, ContractAuditUpdateListVO.class);
        Map<String, ContractAuditUpdateListVO> auditToUpdateMap = contractAuditUpdateVOList.stream().collect(Collectors.groupingBy(ContractAuditUpdateListVO::getContractAuditId
                , Collectors.collectingAndThen(
                        Collectors.toList(), list -> list.stream().findFirst().orElse(null))));
        //查询当前版本合同取消信息
        LambdaQueryWrapper<ContractAuditCancel> cancelQuery = new LambdaQueryWrapper<>();
        List<ContractAuditCancel> contractAuditCancelList = contractAuditCancelService.getEntityList(cancelQuery);
        List<ContractAuditCancelVO> contractAuditCancelVOList = Binder.convertAndBindRelations(contractAuditCancelList, ContractAuditCancelVO.class);
        Map<String, ContractAuditCancelVO> auditToCancelMap = contractAuditCancelVOList.stream().collect(Collectors.groupingBy(ContractAuditCancelVO::getContractAuditId
                , Collectors.collectingAndThen(
                        Collectors.toList(), list -> list.stream().findFirst().orElse(null))));
        for (ContractAuditVO contractAuditVO : contractAuditVOList) {
            contractAuditVO.setContractInfoVO(auditToInfoMap.get(contractAuditVO.getId()));
            contractAuditVO.setContractExtVO(auditToExtMap.get(contractAuditVO.getId()));
            contractAuditVO.setContractProductVOList(auditToProductListMap.get(contractAuditVO.getId()));
            contractAuditVO.setContractAuditUpdateVO(auditToUpdateMap.get(contractAuditVO.getId()));
            contractAuditVO.setContractAuditCancelVO(auditToCancelMap.get(contractAuditVO.getContractCode()));
        }
        pagination.setTotalCount(page.getTotal());
        return contractAuditVOList;
    }

    @Override
    @Transactional
    public String saveContractAudit(ContractAuditVO contractAuditVO) {
        //合同数据校验
        if (StringUtils.isEmpty(contractAuditVO.getId()) && existsContract(contractAuditVO.getContractCode())) {
            throw new BusinessException("合同编号【" + contractAuditVO.getContractCode() + "】已存在！");
        }
        contractAuditVO.getContractInfoVO().setCustomerId(contractAuditVO.getCustomerId());
        contractAuditVO.setContractVersion(NumberUtils.LONG_ONE)
                .setAuditType(ContractAuditTypeEnum.CREATE.getCode());
        List<ContractProductListVO> contractProductVOList = contractAuditVO.getContractProductVOList();
        // 校验sheetNum不能重复
        Set<String> existsSheetNum = new HashSet<>();
        for (ContractProductListVO contractProductListVO : contractProductVOList) {
            if (S.isNotBlank(contractProductListVO.getSheetNum()) && existsSheetNum.contains(contractProductListVO.getSheetNum())) {
                throw new BusinessException("清单页不能重复");
            } else {
                existsSheetNum.add(contractProductListVO.getSheetNum());
            }
        }
        for (ContractProductListVO contractProductListVO : contractProductVOList) {
            Integer rowNum = 10;
            if (contractProductListVO.getContractProductMaterialVOList() == null) {
                continue;
            }
            for (ContractProductMaterialVO contractProductMaterialVO : contractProductListVO.getContractProductMaterialVOList()) {
                String rn = contractProductMaterialVO.getRowNum();
                // 未填写行号自动生成
                if (S.isBlank(rn)) {
                    contractProductMaterialVO.setRowNum(String.valueOf(rowNum));
                    rowNum += 10;
                } else {
                    rowNum = Integer.parseInt(contractProductMaterialVO.getRowNum()) + 10;
                }
            }
        }
        String contractAuditId = this.saveContract(contractAuditVO);
        //if (StringUtils.isEmpty(contractAuditVO.getInstanceId())) {
        //    //创建流程实例
        //    String instanceId = this.createContractProcessInstance(ContractModelKeyConstants.CONTRACT_AUDIT_KEY, contractAuditId);
        //    //绑定流程实例
        //    LambdaUpdateWrapper<ContractAudit> updateWrapper = new LambdaUpdateWrapper<>();
        //    updateWrapper.set(ContractAudit::getInstanceId, instanceId).eq(ContractAudit::getId, contractAuditId);
        //    this.update(updateWrapper);
        //}
        return contractAuditId;
    }

    @Override
    @Transactional
    public void deleteContractAudit(String contractAuditId) {
        ContractAudit contractAudit = this.getEntity(contractAuditId);
        if (!ContractAuditStatusEnum.canDelete(contractAudit.getContractStatus())) {
            throw new BusinessException("合同已提交，不可删除！");
        }
        String contractCode = contractAudit.getContractCode();
        Long contractVersion = contractAudit.getContractVersion();
        contractInfoService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractExtService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractProductService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractProductMaterialService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
//        bpmProcessInstanceService.cancelProcessInstance(contractAudit.getInstanceId(), "删除合同评审");
        this.deleteEntity(contractAuditId);
    }

    @Override
    @Transactional
    public String submitContractAudit(ContractAuditVO contractAuditVO) {
        //合同数据校验
        List<ContractProductListVO> contractProductVOList = contractAuditVO.getContractProductVOList();
        if (contractProductVOList == null || contractProductVOList.isEmpty()) {
            throw new BusinessException("合同产品为空，提交失败！");
        }
        // 红外事业部不校验技术清单
        if (!S.equals("IPL", contractAuditVO.getBusinessModel())) {
            for (ContractProductListVO contractProductListVO : contractProductVOList) {
                List<ContractProductMaterialVO> contractProductMaterialVOList = contractProductListVO.getContractProductMaterialVOList();
                if (contractProductMaterialVOList == null || contractProductMaterialVOList.isEmpty()) {
                    throw new BusinessException("【" + contractProductListVO.getProductCode() + "】技术清单为空，提交失败！");
                }
            }
        }
        String contractAuditId = this.saveContractAudit(contractAuditVO);
        //自动提交第一个用户任务
        //ContractAudit contractAudit = this.getEntity(contractAuditId);
        //String processInstanceId = contractAudit.getInstanceId();
        //bpmProcessTaskService.commitUserTask(processInstanceId);
        return contractAuditId;
    }

    @Override
    @Transactional
    public String saveContractAuditUpdate(ContractAuditVO contractAuditVO) {
        String beforeId = contractAuditVO.getId();
        //校验合同
        if (ObjectUtils.isEmpty(contractAuditVO)) {
            throw new BusinessException("合同评审信息为空，变更失败！");
        }
        String contractCode = contractAuditVO.getContractCode();
        if (!existsContract(contractCode)) {
            throw new BusinessException("合同不存在，变更失败！");
        }
        // 流程状态校验
        if (contractAuditVO.getContractAuditUpdateVO().isSubmit() && !ContractAuditStatusEnum.canUpdate(contractAuditVO.getContractStatus())) {
            throw new BusinessException("正在进行合同评审或合同变更评审，变更失败！");
        }
        ContractAuditUpdateListVO contractAuditUpdateVO = contractAuditVO.getContractAuditUpdateVO();
        if (ObjectUtils.isEmpty(contractAuditUpdateVO)) {
            throw new BusinessException("合同变更评审信息为空，变更失败！");
        }
        Long currentVersion = contractAuditVO.getContractVersion();
        // 没有暂存记录，新增暂存
        if (StringUtils.isEmpty(contractAuditUpdateVO.getId())) {
            QueryWrapper<ContractProduct> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(ContractProduct::getContractAuditId, contractAuditVO.getId());
            List<ContractProduct> orginalContractProductList = contractProductService.getEntityList(queryWrapper);
            String preChangeAmount = orginalContractProductList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getContractPrice()).collect(Collectors.joining(","));
            String preChangeDiscount = orginalContractProductList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getProductDiscount()).collect(Collectors.joining(","));
            String preChangeNum = orginalContractProductList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getProductCount()).collect(Collectors.joining(","));
            String preChangePrice = orginalContractProductList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getProductPrice()).collect(Collectors.joining(","));
            contractAuditUpdateVO.setPreChangeAmount(preChangeAmount);
            contractAuditUpdateVO.setPreChangeDiscount(preChangeDiscount);
            contractAuditUpdateVO.setPreChangeNum(preChangeNum);
            contractAuditUpdateVO.setPreChangePrice(preChangePrice);
            //新增暂存
            currentVersion++;
            this.clear(contractAuditVO, false);
        }
        //保存合同评审
        contractAuditVO.setContractCode(contractCode).setContractVersion(currentVersion)
                .setAuditType(ContractAuditTypeEnum.UPDATE.getCode()).setContractStatus(contractAuditVO.getContractAuditUpdateVO().isSubmit() ? ContractAuditStatusEnum.PROCESSING.getCode() : ContractAuditStatusEnum.NO_SUBMIT.getCode());
        String contractAuditId = this.saveContract(contractAuditVO);
        // 合同id发生改变 复制团队
        if (!S.equals(beforeId, contractAuditId)) {
            List<ContractTeam> contractTeamList = contractTeamService.getTeamsByContractId(beforeId);
            contractTeamList.forEach(e -> {
                e.setContractId(contractAuditId);
                e.setId(null);
            });
            contractTeamService.createEntities(contractTeamList);
        }
        List<ContractProductListVO> contractProductVOList = contractAuditVO.getContractProductVOList();
        String changeAmount = contractProductVOList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getContractPrice()).collect(Collectors.joining(","));
        String changeDiscount = contractProductVOList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getProductDiscount()).collect(Collectors.joining(","));
        String changeNum = contractProductVOList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getProductCount()).collect(Collectors.joining(","));
        String changePrice = contractProductVOList.stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getProductPrice()).collect(Collectors.joining(","));
        //保存合同变更评审
        ContractAuditUpdate contractAuditUpdate = BeanUtils.convert(contractAuditUpdateVO, ContractAuditUpdate.class);
        contractAuditUpdate.setContractCode(contractCode)
                .setChangedAmount(changeAmount)
                .setChangedDiscount(changeDiscount)
                .setChangedNum(changeNum)
                .setChangedPrice(changePrice)
                .setContractVersion(currentVersion).setTenantId(contractAuditVO.getTenantId()).setContractAuditId(contractAuditVO.getId());
        contractAuditUpdateService.createOrUpdateEntity(contractAuditUpdate);
        //if (StringUtils.isEmpty(contractAuditVO.getInstanceId())) {
        //    //创建流程实例
        //    String instanceId = this.createContractProcessInstance(ContractModelKeyConstants.CONTRACT_AUDIT_UPDATE_KEY, contractAuditId);
        //    //绑定流程实例
        //    LambdaUpdateWrapper<ContractAudit> updateWrapper = new LambdaUpdateWrapper<>();
        //    updateWrapper.set(ContractAudit::getInstanceId, instanceId).set(ContractAudit::getContractStatus, ContractAuditStatusEnum.PROCESSING.getCode()).eq(ContractAudit::getId, contractAuditId);
        //    this.update(updateWrapper);
        //}
        return contractAuditId;
    }

    @Override
    @Transactional
    public void deleteContractAuditUpdate(String contractAuditId) {
        ContractAudit contractAudit = this.getEntity(contractAuditId);
        if (!ContractAuditStatusEnum.canDelete(contractAudit.getContractStatus())) {
            throw new BusinessException("合同已提交，不可删除！");
        }
        String contractCode = contractAudit.getContractCode();
        Long contractVersion = contractAudit.getContractVersion();
        contractInfoService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractExtService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractProductService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractProductMaterialService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractAuditUpdateService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        //bpmProcessInstanceService.cancelProcessInstance(contractAudit.getInstanceId(), "删除合同变更评审");
        this.deleteEntity(contractAuditId);
    }

    @Override
    @Transactional
    public String submitContractAuditUpdate(ContractAuditVO contractAuditVO) {
        String contractAuditId = this.saveContractAuditUpdate(contractAuditVO);
//        List<ContractProductListVO> contractProductVOList = contractAuditVO.getContractProductVOList();
        //contractProductVOList.forEach(contractProductListVO -> {
        //    contractProductListVO.setSapContractPushStatus("1"); // 未推送
        //});
//        contractProductService.updateEntities(contractProductVOList);
        ContractAudit contractAudit = this.getEntity(contractAuditId);
        // 修改历史版本状态
        UpdateWrapper<ContractAudit> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(ContractAudit::getContractStatus, ContractAuditStatusEnum.HISTORY.getCode())
                .eq(ContractAudit::getContractCode, contractAudit.getContractCode())
                .ne(ContractAudit::getId, contractAudit.getId());
        update(updateWrapper);
        //自动提交第一个用户任务
        //String processInstanceId = contractAudit.getInstanceId();
        //bpmProcessTaskService.commitUserTask(processInstanceId);
        return contractAuditId;
    }

    @Override
    public List<ContractAuditVO> getContractAuditHistory(ContractAuditVO contractAuditVO) {
        return contractAuditMapper.selectHistoryContractList(contractAuditVO);
    }

    @Override
    @Transactional
    public String saveContractAuditCancel(ContractAuditCancelVO contractAuditCancelVO) {
        String contractCode = contractAuditCancelVO.getContractCode();
        //合同数据校验
        if (!existsContract(contractCode)) {
            throw new BusinessException("合同不存在!");
        }
        //校验成功
        //将之前的审批流程取消
        LambdaQueryWrapper<ContractAudit> contractAuditLambdaQueryWrapper = new LambdaQueryWrapper<>();
        contractAuditLambdaQueryWrapper.eq(ContractAudit::getContractCode, contractCode).eq(ContractAudit::isDeleted, 0)
                .ne(ContractAudit::getContractStatus, ContractAuditStatusEnum.NO_SUBMIT.getCode()).orderByDesc(ContractAudit::getContractVersion);
        ContractAudit hisContractAudit = this.getSingleEntity(contractAuditLambdaQueryWrapper);
        if (!ContractAuditStatusEnum.canCancel(hisContractAudit.getContractStatus())) {
            throw new BusinessException("当前合同无法取消!");
        }
        // 流程
        //if (contractAuditCancelVO.isSubmit()) {
        //    //取消历史版本的流程
        //    String instanceId = hisContractAudit.getInstanceId();
        //    bpmProcessInstanceService.cancelProcessInstance(instanceId, "合同变更评审");
        //    //修改历史版本审批状态
        //    hisContractAudit.setAuditType(ContractAuditStatusEnum.HISTORY.getCode());
        //    this.updateEntity(hisContractAudit);
        //}
        ContractAuditVO contractAuditVO = getContractDetail(hisContractAudit.getId());
        // 修改
        //contractAuditVO.setContractStatus(ContractAuditStatusEnum.HISTORY.getCode());
        //updateEntity(contractAuditVO);
        long currentVersion = hisContractAudit.getContractVersion();
        //if (StringUtils.isEmpty(contractAuditCancelVO.getId())) {
        //    //如果ID为空,hisContractAudit为上一版本合同,ID不为空,则hisContractAudit为上次暂存保存的结果
        //    clear(contractAuditVO);
        //    currentVersion++;
        //}
        ContractAuditCancel contractAuditCancel = BeanUtils.convert(contractAuditCancelVO, ContractAuditCancel.class);
        contractAuditCancel.setContractCode(contractCode).setContractVersion(currentVersion).setTenantId(hisContractAudit.getTenantId());
        contractAuditCancelService.createOrUpdateEntity(contractAuditCancel);
        contractAuditVO.setContractCode(contractAuditCancel.getContractCode()).setContractVersion(contractAuditCancel.getContractVersion())
                .setAuditType("cancel").setContractStatus(ContractAuditStatusEnum.PROCESSING.getCode());
        String contractAuditId = this.saveContract(contractAuditVO);
        // 流程引擎
/*        if (StringUtils.isEmpty(contractAuditVO.getInstanceId())) {
            //创建流程实例
            String instanceId = this.createContractProcessInstance(ContractModelKeyConstants.CONTRACT_AUDIT_CANCEL_KEY, contractAuditId);
            //绑定流程实例
            LambdaUpdateWrapper<ContractAudit> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(ContractAudit::getInstanceId, instanceId).set(ContractAudit::getContractStatus, ContractAuditStatusEnum.PROCESSING.getCode()).eq(ContractAudit::getId, contractAuditId);
            this.update(updateWrapper);
        }*/
        return contractAuditVO.getId();
    }

    @Override
    @Transactional
    public void deleteContractAuditCancel(String contractAuditId) {
        ContractAudit contractAudit = this.getEntity(contractAuditId);
        if (!ContractAuditStatusEnum.canDelete(contractAudit.getContractStatus())) {
            throw new BusinessException("合同已提交，不可删除！");
        }
        String contractCode = contractAudit.getContractCode();
        Long contractVersion = contractAudit.getContractVersion();
        contractInfoService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractExtService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractProductService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractProductMaterialService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        contractAuditCancelService.deleteByContractCodeAndContractVersion(contractCode, contractVersion);
        bpmProcessInstanceService.cancelProcessInstance(contractAudit.getInstanceId(), "删除合同取消评审");
        this.deleteEntity(contractAuditId);
    }

    @Override
    @Transactional
    public String submitContractAuditCancel(ContractAuditCancelVO contractAuditCancelVO) {
        String contractAuditId = this.saveContractAuditCancel(contractAuditCancelVO);
        //ContractAudit contractAudit = this.getEntity(contractAuditId);
        // 流程引擎
        //bpmProcessTaskService.commitUserTask(contractAudit.getInstanceId());
        return contractAuditId;
    }

    @Override
    @Transactional
    public String saveContract(ContractAuditVO contractAuditVO) {
        if (S.isBlank(contractAuditVO.getId())) {
            contractAuditVO.setId(null);
        }
        contractAuditVO.setAccountDistribution(S.equals("01", contractAuditVO.getAccountDistribution()) ? "20" : S.equals("02", contractAuditVO.getAccountDistribution()) ? "10" : contractAuditVO.getAccountDistribution());
        BaseLoginUser currentUser = IamSecurityUtils.getCurrentUser();
        //新增合同审批信息
        contractAuditVO.setTenantId(currentUser.getTenantId())
                .setAuditType(contractAuditVO.getAuditType()).setOaStatus(OAStatusEnum.NO.getCode()).setSapStatus(SAPStatusEnum.NO.getCode());
        this.createOrUpdateEntity(contractAuditVO);
        //新增合同基础信息
        ContractInfoListVO contractInfoVO = contractAuditVO.getContractInfoVO();
        contractInfoVO.setContractAuditId(contractAuditVO.getId()).setContractCode(contractAuditVO.getContractCode()).setContractVersion(contractAuditVO.getContractVersion()).setTenantId(currentUser.getTenantId());
        contractInfoService.createOrUpdateEntity(contractInfoVO);

        //如果是公司合同模版,新增合同扩展信息（详细合同内容）
        if ("10".equals(contractInfoVO.getCompanyTemplate())) {
            ContractExtListVO contractExtVO = contractAuditVO.getContractExtVO();
            contractExtVO.setContractAuditId(contractAuditVO.getId()).setContractCode(contractAuditVO.getContractCode()).setContractVersion(contractAuditVO.getContractVersion()).setTenantId(currentUser.getTenantId());
            contractExtService.createOrUpdateEntity(contractExtVO);
        }

        //新增合同产品信息
        List<ContractProductListVO> contractProductVOList = contractAuditVO.getContractProductVOList();
        contractProductVOList = contractProductVOList.stream().peek(item -> item.setContractAuditId(contractAuditVO.getId()).setContractCode(contractAuditVO.getContractCode()).setContractVersion(contractAuditVO.getContractVersion()).setTenantId(currentUser.getTenantId())).collect(Collectors.toList());
        contractProductService.createOrUpdateEntities(contractProductVOList);

        // 删除不存在的物料
        if (contractProductVOList.size() > 0) {
            LambdaQueryWrapper<ContractProductMaterial> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(ContractProductMaterial::getContractProductId, BeanUtils.collectToList(contractProductVOList, ContractProductListVO::getId));
            List<ContractProductMaterial> materialVOList = contractProductMaterialService.getEntityList(queryWrapper);
            // 数据库中的物料
            Map<String, List<ContractProductMaterial>> materialMap = materialVOList.stream().collect(Collectors.groupingBy(ContractProductMaterial::getContractProductId));
            // 前端提交的物料
            Map<String, List<ContractProductMaterialVO>> materialVOMap = contractProductVOList.stream().flatMap(item -> {
                if (item.getContractProductMaterialVOList() != null) {
                    return item.getContractProductMaterialVOList().stream();
                } else {
                    return Stream.empty();
                }
            }).filter(item -> StringUtils.isNotBlank(item.getContractProductId())).collect(Collectors.groupingBy(ContractProductMaterialVO::getContractProductId));
            // 收集前端未提交的物料
            List<ContractProductMaterial> deleteMaterialList = new ArrayList<>();
            for (String contractProductId : materialMap.keySet()) {
                List<ContractProductMaterialVO> contractProductMaterialVOList = materialVOMap.get(contractProductId);
                List<ContractProductMaterial> contractProductMaterialList = materialMap.get(contractProductId);
                if (contractProductMaterialList == null) {
                    contractProductMaterialList = new ArrayList<>();
                }
                List<ContractProductMaterial> deleteList = contractProductMaterialList.stream().filter(item -> contractProductMaterialVOList == null || contractProductMaterialVOList.stream().noneMatch(item1 -> Objects.equals(item1.getRowNum(), item.getRowNum()))).toList();
                if (!deleteList.isEmpty()) {
                    deleteMaterialList.addAll(deleteList);
                }
            }
            // 删除
            contractProductMaterialService.deleteEntities(deleteMaterialList);
        }
        List<ContractProductMaterialVO> allContractProductMaterialVOList = new ArrayList<>();
        //新增产品物料技术清单
        for (ContractProductListVO contractProductVO : contractProductVOList) {
            List<ContractProductMaterialVO> contractProductMaterialVOList = contractProductVO.getContractProductMaterialVOList();
            if (contractProductMaterialVOList == null) {
                continue;
            }
            contractProductMaterialVOList = contractProductMaterialVOList.stream().peek(item -> item.setProductCode(contractProductVO.getProductCode()).setProductType(contractProductVO.getProductType()).setContractProductId(contractProductVO.getId()).setContractCode(contractAuditVO.getContractCode()).setContractVersion(contractAuditVO.getContractVersion()).setTenantId(currentUser.getTenantId())).collect(Collectors.toList());
            allContractProductMaterialVOList.addAll(contractProductMaterialVOList);
        }
        contractProductMaterialService.createOrUpdateEntities(allContractProductMaterialVOList);
        return contractAuditVO.getId();
    }

    @Override
    @Transactional
    public void approveContract(ContractAuditTaskVO contractAuditTaskVO) {
        ContractAuditVO contractAuditVO = contractAuditTaskVO.getContractAuditVO();
        if (ObjectUtils.isEmpty(contractAuditVO)) {
            throw new BusinessException("任务处理失败!");
        }
        this.updateEntity(contractAuditVO);
        contractInfoService.updateEntity(contractAuditVO.getContractInfoVO());
        contractExtService.updateEntity(contractAuditVO.getContractExtVO());
        List<ContractProductListVO> contractProductVOList = contractAuditVO.getContractProductVOList();
        contractProductService.updateEntities(contractProductVOList);
        List<ContractProductMaterialVO> allContractProductMaterialVOList = new ArrayList<>();
        for (ContractProductListVO contractProductVO : contractProductVOList) {
            allContractProductMaterialVOList.addAll(contractProductVO.getContractProductMaterialVOList());
        }
        contractProductMaterialService.updateEntities(allContractProductMaterialVOList);
        //BpmTaskApproveReqVO bpmTaskApproveReqVO = new BpmTaskApproveReqVO();
        //bpmTaskApproveReqVO.setId(contractAuditTaskVO.getTaskId());
        //bpmTaskApproveReqVO.setReason(contractAuditTaskVO.getReason());
        //bpmTaskApproveReqVO.setCopyUserIds(contractAuditTaskVO.getCopyUserIds());
        //bpmProcessTaskService.approveTask(bpmTaskApproveReqVO);
    }

    public String createContractProcessInstance(String modelKey, String businessKey) {
        String processDefinitionId = bpmProcessDefinitionService.getBpmProcessDefinitionIdByKey(modelKey);
        BpmProcessInstanceCreateReqVO bpmProcessInstanceCreateReqVO = new BpmProcessInstanceCreateReqVO();
        bpmProcessInstanceCreateReqVO.setProcessDefinitionId(processDefinitionId).setBusinessKey(businessKey);
        return bpmProcessInstanceService.createProcessInstance(bpmProcessInstanceCreateReqVO);
    }

    private boolean existsContract(String contractCode) {
        QueryWrapper<ProjectContractAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().select(ProjectContractAudit::getId).eq(ProjectContractAudit::getContractCode, contractCode);
        List<ProjectContractAudit> projectContractAudits = projectContractAuditMapper.selectList(queryWrapper);
        if (projectContractAudits != null && !projectContractAudits.isEmpty()) {
            return true;
        }
        LambdaQueryWrapper<ContractInfo> contractInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        contractInfoLambdaQueryWrapper.eq(ContractInfo::getContractCode, contractCode);
        return contractInfoService.exists(contractInfoLambdaQueryWrapper);
    }

    /**
     * 检查合同是否可以归档
     * <p>
     * 此方法旨在确定合同审批状态和收款金额是否满足归档条件具体来说，它检查两个条件：
     * 1. 合同审批状态是否允许归档
     * 2. 合同收款金额是否等于总金额
     * 如果任何一个条件不满足，则抛出业务异常，表明合同不能归档
     *
     * @param contractAuditId 合同审批ID，用于获取合同审批对象
     * @throws BusinessException 如果合同审批未完成或收款未完成，则抛出此异常
     */
    private void canArchive(String contractAuditId) {
        // 根据合同审批ID获取合同审批对象
        ContractAudit contractAudit = this.getEntity(contractAuditId);

        // 检查合同当前状态是否允许归档
        boolean statusCanArchive = ContractAuditStatusEnum.canArchive(contractAudit.getContractStatus());
        // 如果合同审批状态不允许归档，抛出异常
        if (!statusCanArchive) {
            throw new BusinessException("合同审批未完成，无法归档！");
        }
        // 准备查询条件以获取合同信息
        LambdaQueryWrapper<ContractInfo> contractInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        contractInfoLambdaQueryWrapper.eq(ContractInfo::getContractCode, contractAudit.getContractCode())
                .eq(ContractInfo::getContractVersion, contractAudit.getContractVersion()).eq(ContractInfo::isDeleted, 0);

        // 根据查询条件获取合同信息
        ContractInfo contractInfo = contractInfoService.getSingleEntity(contractInfoLambdaQueryWrapper);

        // 获取合同已收款金额和总金额
        BigDecimal receivedAmount = contractInfo.getReceivedAmount();
        BigDecimal totalAmount = contractInfo.getTotalAmount();

        // 比较已收款金额和总金额，判断是否可以归档
        int compareResult = receivedAmount.compareTo(totalAmount);
        boolean amountCanArchive = compareResult == 0;


        // 如果合同收款金额不等于总金额，抛出异常
        if (!amountCanArchive) {
            throw new BusinessException("合同收款未完成，无法归档！");
        }
    }

    private ContractAuditVO clear(ContractAuditVO contractAuditVO, Boolean isCopy) {
        contractAuditVO.setContractCode(null)
                .setContractVersion(null).setContractStatus(null).setAuditType(null)
                .setOaStatus(null).setOaMsg(null)
                .setSapStatus(null).setSapMsg(null)
                .setInstanceId(null).setTenantId(null)
                .setUpdateBy(null).setUpdateTime(null)
                .setCreateBy(null).setCreateTime(null)
                .setId(null);
        ContractInfoListVO contractInfoVO = contractAuditVO.getContractInfoVO();
        contractInfoVO.setContractAuditId(null).setContractCode(null).setContractVersion(null).setTenantId(null)
                .setUpdateBy(null).setUpdateTime(null)
                .setCreateBy(null).setCreateTime(null)
                .setId(null);

        if (isCopy) {
            contractAuditVO.setSapCode(null);
            contractAuditVO.setOaStatus(OAStatusEnum.NO.getCode());
            contractAuditVO.setSapStatus(SAPStatusEnum.NO.getCode());
            contractInfoVO.setReceivedAmount(BigDecimal.ZERO);
            contractInfoVO.setOutstandingAmount(contractInfoVO.getTotalAmount());
        }
        ContractExtListVO contractExtVO = contractAuditVO.getContractExtVO();
        if (ObjectUtils.isNotEmpty(contractExtVO)) {
            contractExtVO.setContractAuditId(null).setContractCode(null).setContractVersion(null).setTenantId(null)
                    .setUpdateBy(null).setUpdateTime(null)
                    .setCreateBy(null).setCreateTime(null)
                    .setId(null);
        }
        List<ContractProductListVO> contractProductVOList = contractAuditVO.getContractProductVOList();
        if (contractProductVOList == null || contractProductVOList.isEmpty()) {
            return contractAuditVO;
        }
        for (ContractProductListVO contractProductVO : contractProductVOList) {
            if (isCopy) {
                contractProductVO.setContractAuditId(null)
                        .setContractCode(null)
                        .setContractVersion(null)
                        .setSapContractCode(null)
                        .setSapContractCancel(null)
                        .setTenantId(null)
                        .setSapContractPushStatus("1")
                        .setSapContractId(null)
                        .setLastNum(0)
                        .setUpdateBy(null)
                        .setUpdateTime(null)
                        .setCreateBy(null)
                        .setCreateTime(null)
                        .setId(null);
            } else {
                contractProductVO.setContractAuditId(null).setId(null);
            }
            List<ContractProductMaterialVO> contractProductMaterialVOList = contractProductVO.getContractProductMaterialVOList();
            if (contractProductMaterialVOList == null || contractProductMaterialVOList.isEmpty()) {
                continue;
            }
            for (ContractProductMaterialVO contractProductMaterialVO : contractProductMaterialVOList) {
                if (isCopy) {
                    contractProductMaterialVO
                            .setContractProductId(null)
                            .setContractCode(null)
                            .setContractVersion(null)
                            .setTenantId(null)
                            .setUpdateBy(null).setUpdateTime(null)
                            .setCreateBy(null).setCreateTime(null)
                            .setId(null);
                } else {
                    contractProductMaterialVO.setContractProductId(null).setId(null);
                }
            }
        }
        return contractAuditVO;
    }

    /**
     * 对比物料清单
     *
     * @return
     * @author 陈广煜
     * @date 2024-08-19
     */
    public List<ContractProductMaterialVO> compareMaterial(String customerId, String org, List<ContractProductMaterialVO> mrlList) {
        List<String> mrlCodeList = BeanUtils.collectToList(mrlList, ContractProductMaterialVO::getMaterialCode);
        SapCustomer customer = customerService.getEntity(customerId);
        if (customer == null) {
            throw new BusinessException("客户不存在");
        }
        if (S.isBlank(customer.getSapNo())) {
            throw new BusinessException("客户SAP编码为空");
        }
        // sap物料清单
        List<Konp> sapMrl = konpService.getSapMrl(customer.getSapNo(), org, mrlCodeList);
        if (sapMrl.isEmpty()) {
            sapMrl = konpService.getSapMrl(org, mrlCodeList);
        }
        Map<String, Konp> konpMap = new HashMap<>();
        for (Konp konp : sapMrl) {
            konpMap.put(konp.getMatnr(), konp);
        }
        for (ContractProductMaterialVO materialVO : mrlList) {
            Konp konp = konpMap.get(materialVO.getMaterialCode());
            if (konp == null) {
                materialVO.setCompareResult("该物料编码SAP中未找到");
            } else if (!S.equals(materialVO.getMaterialPrice().setScale(2, RoundingMode.FLOOR).toPlainString(), konp.getKbetr())) {
                materialVO.setCompareResult("该物料单价与SAP不一致");
            } else {
                materialVO.setCompareResult("一致");
            }
        }
        return mrlList;
    }


    @Override
    @Transactional
    public List<DiffVO> getDiff(String id) {
        ContractAuditVO newest = getViewObject(id, ContractAuditVO.class);
//        newest = Binder.convertAndBindRelations(newest, ContractAuditVO.class);
        Long contractVersion = newest.getContractVersion();
        QueryWrapper<ContractAudit> qw = new QueryWrapper<>();
        qw.lambda().select(ContractAudit::getId)
                .eq(ContractAudit::getContractCode, newest.getContractCode())
                .eq(ContractAudit::getContractVersion, --contractVersion);
        //.eq(ContractAudit::getContractStatus, ContractAuditStatusEnum.NO_SUBMIT);
        ContractAudit last = getSingleEntity(qw);
        if (last == null) {
            return null;
        }
        ContractAuditVO contractDetail = getContractDetail(last.getId());
        // 比较产品物料
        List<ContractProductListVO> productVOList = contractDetail.getContractProductVOList();
        List<ContractProductListVO> newestProductVOList = newest.getContractProductVOList();
        return compareProductMrlLists(productVOList, newestProductVOList);
    }

    @Override
    public List<ChangeMrlVO> getCncDiff(String id) {
        ContractAuditVO newest = getViewObject(id, ContractAuditVO.class);
//        newest = Binder.convertAndBindRelations(newest, ContractAuditVO.class);
        Long contractVersion = newest.getContractVersion();
        QueryWrapper<ContractAudit> qw = new QueryWrapper<>();
        qw.lambda().select(ContractAudit::getId)
                .eq(ContractAudit::getContractCode, newest.getContractCode())
                .eq(ContractAudit::getContractVersion, --contractVersion);
        //.eq(ContractAudit::getContractStatus, ContractAuditStatusEnum.NO_SUBMIT);
        ContractAudit last = getSingleEntity(qw);
        if (last == null) {
            return null;
        }
        ContractAuditVO contractDetail = getContractDetail(last.getId());
        // 比较产品物料
        List<ContractProductListVO> productVOList = contractDetail.getContractProductVOList();
        List<ContractProductListVO> newestProductVOList = newest.getContractProductVOList();
        return compareCncProductMrlLists(productVOList, newestProductVOList);
    }

    private static List<ChangeMrlVO> compareCncProductMrlLists(List<ContractProductListVO> oldList, List<ContractProductListVO> newList) {
        // 如果任一列表为空，则直接返回空列表
        if (oldList == null || newList == null) {
            return Collections.emptyList();
        }

        // 将旧产品列表转换为字典，便于后续比较
        Map<String, ContractProductListVO> oldMap = new HashMap<>();
        for (ContractProductListVO contractProductListVO : oldList) {
            oldMap.put(contractProductListVO.getSheetNum(), contractProductListVO);
        }

        // 将新产品列表转换为字典，便于后续比较
        Map<String, ContractProductListVO> newMap = new HashMap<>();
        for (ContractProductListVO contractProductListVO : newList) {
            newMap.put(contractProductListVO.getSheetNum(), contractProductListVO);
        }

        // 找出两个列表中共有的产品
        Set<String> commonProducts = new HashSet<>(oldMap.keySet());
        commonProducts.retainAll(newMap.keySet());

        // 初始化差异列表
        List<ChangeMrlVO> DiffVOs = new ArrayList<>();

        // 遍历共有产品，比较每个产品的详细信息
        for (String productKey : commonProducts) {
            String machineModel = "";
            String productModel = "";
            List<ContractProductMaterialVO> oldMaterials = new ArrayList<>();
            ContractProductListVO contractProductVO = oldMap.get(productKey);
            if (contractProductVO != null) {
                oldMaterials = contractProductVO.getContractProductMaterialVOList() == null ? new ArrayList<>() : contractProductVO.getContractProductMaterialVOList();
                machineModel = contractProductVO.getMachineType();
                productModel = contractProductVO.getProductType();
            }
            List<ContractProductMaterialVO> newMaterials = new ArrayList<>();
            ContractProductListVO contractProductVONew = newMap.get(productKey);
            if (contractProductVONew != null) {
                newMaterials = contractProductVONew.getContractProductMaterialVOList() == null ? new ArrayList<>() : contractProductVONew.getContractProductMaterialVOList();
                machineModel = contractProductVONew.getMachineType();
                productModel = contractProductVONew.getProductType();
            }

            // 将旧产品和新产品的物料列表转换为字典
            Map<String, ContractProductMaterialVO> oldMrlMap = new HashMap<>();
            for (ContractProductMaterialVO oldMaterial : oldMaterials) {
                oldMrlMap.put(oldMaterial.getRowNum(), oldMaterial);
            }
            Map<String, ContractProductMaterialVO> newMrlMap = new HashMap<>();
            for (ContractProductMaterialVO newMaterial : newMaterials) {
                newMrlMap.put(newMaterial.getRowNum(), newMaterial);
            }

            // 比较新旧物料列表的差异
            for (Map.Entry<String, ContractProductMaterialVO> entry : newMrlMap.entrySet()) {
                ContractProductMaterialVO oldMaterial = oldMrlMap.get(entry.getKey());
                ContractProductMaterialVO mrl = entry.getValue();
                if (oldMaterial == null) {
                    // 新增物料
                    DiffVOs.add(new ChangeMrlVO(machineModel, productModel, mrl.getMaterialCode(), mrl.getMaterialDesc(), mrl.getMaterialCount() + "", mrl.getRemark(), true));
                    continue;
                }
//                // 变更物料
//                if (!Objects.equals(oldMaterial.getMaterialDesc(), entry.getValue().getMaterialDesc()) ||
//                        !Objects.equals(oldMaterial.getMaterialCount(), entry.getValue().getMaterialCount()) ||
//                        !Objects.equals(oldMaterial.getMaterialCode(), entry.getValue().getMaterialCode())) {
//                    DiffVOs.add(new DiffVO(productKey, oldMaterial.getMaterialCode(), oldMaterial.getMaterialDesc(), oldMaterial.getMaterialCount(), entry.getValue().getMaterialCode(), entry.getValue().getMaterialDesc(), entry.getValue().getMaterialCount()).setBeforeRemark("变更").setAfterRemark("变更").setBeforeNum(oldMaterial.getRowNum() + "").setAfterNum(entry.getValue().getRowNum() + ""));
//                }
            }

            // 找出删除的物料
            Set<String> newKeys = newMrlMap.keySet();
            Set<String> oldKeys = oldMrlMap.keySet();
            Set<String> removeMrls = new HashSet<>(oldKeys);
            removeMrls.removeAll(newKeys);
            for (String removeMrl : removeMrls) {
                ContractProductMaterialVO mrl = oldMrlMap.get(removeMrl);
                DiffVOs.add(new ChangeMrlVO(machineModel, productModel, mrl.getMaterialCode(), mrl.getMaterialDesc(), mrl.getMaterialCount() + "", mrl.getRemark(), false));
            }
        }

        // 找出两个列表中只存在于旧列表的产品
        Set<String> oldOnlyProducts = new HashSet<>(oldMap.keySet());
        oldOnlyProducts.removeAll(newMap.keySet());

        for (String productKey : oldOnlyProducts) {
            ContractProductListVO contractProductVO = oldMap.get(productKey);
            if (contractProductVO != null) {
                List<ContractProductMaterialVO> oldMaterials = contractProductVO.getContractProductMaterialVOList() == null ? new ArrayList<>() : contractProductVO.getContractProductMaterialVOList();
                String machineModel = contractProductVO.getMachineType();
                String productModel = contractProductVO.getProductType();
                for (ContractProductMaterialVO mrl : oldMaterials) {
                    DiffVOs.add(new ChangeMrlVO(machineModel, productModel, mrl.getMaterialCode(), mrl.getMaterialDesc(), mrl.getMaterialCount() + "", mrl.getRemark(), false));
                }
            }
        }

        // 找出两个列表中只存在于新产品列表的产品
        Set<String> newOnlyProducts = new HashSet<>(newMap.keySet());
        newOnlyProducts.removeAll(oldMap.keySet());

        for (String productKey : newOnlyProducts) {
            ContractProductListVO contractProductVONew = newMap.get(productKey);
            if (contractProductVONew != null) {
                List<ContractProductMaterialVO> newMaterials = contractProductVONew.getContractProductMaterialVOList() == null ? new ArrayList<>() : contractProductVONew.getContractProductMaterialVOList();
                String machineModel = contractProductVONew.getMachineType();
                String productModel = contractProductVONew.getProductType();
                for (ContractProductMaterialVO mrl : newMaterials) {
                    DiffVOs.add(new ChangeMrlVO(machineModel, productModel, mrl.getMaterialCode(), mrl.getMaterialDesc(), mrl.getMaterialCount() + "", mrl.getRemark(), true));
                }
            }
        }

        // 返回差异列表
        return DiffVOs;
    }


    @Override
    public List<DiffVO> getDiff(String id, List<ContractProductListVO> contractProductVOList) {
        if (contractProductVOList != null && !contractProductVOList.isEmpty()) {
            List<ContractProductListVO> productVOList = getContractDetail(id).getContractProductVOList();
            return compareProductMrlLists(productVOList, contractProductVOList);
        }
        return null;
    }

    /**
     * 比较产品列表
     *
     * @param oldList 旧产品列表
     * @param newList 新产品列表
     * @return 对比结果
     * @author 陈广煜
     * @date 2024-08-21
     */
    private List<DiffVO> compareProductMrlLists(List<ContractProductListVO> oldList, List<ContractProductListVO> newList) {
        // 如果任一列表为空，则直接返回空列表
        if (oldList == null || newList == null) {
            return Collections.emptyList();
        }
        IamTenant tenant = iamTenantService.getEntity(IamSecurityUtils.getCurrentTenantId());
        // 将旧产品列表转换为字典，便于后续比较
        Map<String, ContractProductListVO> oldMap = new HashMap<>();
        for (int i = 0; i < oldList.size(); i++) {
            ContractProductListVO contractProductListVO = oldList.get(i);
            if (S.equals(tenant.getCode(), "skxt")) {
                oldMap.put(contractProductListVO.getSheetNum(), contractProductListVO);
            } else {
                oldMap.put(contractProductListVO.getProductCode(), contractProductListVO);
            }
        }

        // 将新产品列表转换为字典，便于后续比较
        Map<String, ContractProductListVO> newMap = new HashMap<>();
        for (int i = 0; i < newList.size(); i++) {
            ContractProductListVO contractProductListVO = newList.get(i);
            if (S.equals(tenant.getCode(), "skxt")) {
                newMap.put(contractProductListVO.getSheetNum(), contractProductListVO);
            } else {
                newMap.put(contractProductListVO.getProductCode(), contractProductListVO);
            }
        }

        // 找出两个列表中共有的产品
        Set<String> commonProducts = new HashSet<>(oldMap.keySet());
        commonProducts.retainAll(newMap.keySet());

        // 初始化差异列表
        List<DiffVO> DiffVOs = new ArrayList<>();

        // 遍历共有产品，比较每个产品的详细信息
        for (String productKey : commonProducts) {

            List<ContractProductMaterialVO> oldMaterials = new ArrayList<>();
            ContractProductListVO contractProductVO = oldMap.get(productKey);
            if (contractProductVO != null) {
                oldMaterials = contractProductVO.getContractProductMaterialVOList() == null ? new ArrayList<>() : contractProductVO.getContractProductMaterialVOList();
            }
            List<ContractProductMaterialVO> newMaterials = new ArrayList<>();
            ContractProductListVO contractProductVONew = newMap.get(productKey);
            if (contractProductVONew != null) {
                newMaterials = contractProductVONew.getContractProductMaterialVOList() == null ? new ArrayList<>() : contractProductVONew.getContractProductMaterialVOList();
            }

            // 将旧产品和新产品的物料列表转换为字典
            Map<String, ContractProductMaterialVO> oldMrlMap = new HashMap<>();
            for (ContractProductMaterialVO oldMaterial : oldMaterials) {
                oldMrlMap.put(oldMaterial.getRowNum(), oldMaterial);
            }
            Map<String, ContractProductMaterialVO> newMrlMap = new HashMap<>();
            for (ContractProductMaterialVO newMaterial : newMaterials) {
                newMrlMap.put(newMaterial.getRowNum(), newMaterial);
            }

            // 比较新旧物料列表的差异
            for (Map.Entry<String, ContractProductMaterialVO> entry : newMrlMap.entrySet()) {
                ContractProductMaterialVO oldMaterial = oldMrlMap.get(entry.getKey());
                if (oldMaterial == null) {
                    // 新增物料
                    DiffVOs.add(new DiffVO(null, productKey, null, null, null, null, entry.getValue().getRowNum() + "", entry.getValue().getMaterialCode(), entry.getValue().getMaterialDesc(), entry.getValue().getMaterialCount(), "新增"));
                    continue;
                }
                // 变更物料
                if (!Objects.equals(oldMaterial.getMaterialDesc(), entry.getValue().getMaterialDesc()) ||
                        !Objects.equals(oldMaterial.getMaterialCount(), entry.getValue().getMaterialCount()) ||
                        !Objects.equals(oldMaterial.getMaterialCode(), entry.getValue().getMaterialCode())) {
                    DiffVOs.add(new DiffVO(productKey, oldMaterial.getMaterialCode(), oldMaterial.getMaterialDesc(), oldMaterial.getMaterialCount(), entry.getValue().getMaterialCode(), entry.getValue().getMaterialDesc(), entry.getValue().getMaterialCount()).setBeforeRemark("变更").setAfterRemark("变更").setBeforeNum(oldMaterial.getRowNum() + "").setAfterNum(entry.getValue().getRowNum() + ""));
                }
            }

            // 找出删除的物料
            Set<String> newKeys = newMrlMap.keySet();
            Set<String> oldKeys = oldMrlMap.keySet();
            Set<String> removeMrls = new HashSet<>(oldKeys);
            removeMrls.removeAll(newKeys);
            for (String removeMrl : removeMrls) {
                ContractProductMaterialVO mrl = oldMrlMap.get(removeMrl);
                DiffVOs.add(new DiffVO(productKey, mrl.getMaterialCode(), mrl.getMaterialDesc(), mrl.getMaterialCount(), null, null, null).setBeforeRemark("删除").setBeforeNum(mrl.getRowNum() + ""));
            }
        }

        // 找出新增的产品
        Set<String> newProducts = new HashSet<>(newMap.keySet());
        newProducts.removeAll(oldMap.keySet());

        for (String newProductKey : newProducts) {
            ContractProductListVO contractProductVO = newMap.get(newProductKey);
            if (contractProductVO == null || contractProductVO.getContractProductMaterialVOList() == null){
                continue;
            }
            contractProductVO.getContractProductMaterialVOList().forEach(mrl -> {
                DiffVOs.add(new DiffVO(null, newProductKey, null, null, null, null, mrl.getRowNum() + "", mrl.getMaterialCode(), mrl.getMaterialDesc(), mrl.getMaterialCount(), "新增"));
            });
        }

        // 找出删除的产品
        Set<String> removedProducts = new HashSet<>(oldMap.keySet());
        removedProducts.removeAll(newMap.keySet());

        for (String removedProductKey : removedProducts) {
            ContractProductListVO contractProductListVO = oldMap.get(removedProductKey);
            if (contractProductListVO == null || contractProductListVO.getContractProductMaterialVOList() == null){
                continue;
            }
            contractProductListVO.getContractProductMaterialVOList().forEach(mrl -> {
                DiffVOs.add(new DiffVO(removedProductKey, mrl.getMaterialCode(), mrl.getMaterialDesc(), mrl.getMaterialCount(), null, null, null).setBeforeRemark("删除").setBeforeNum(mrl.getRowNum() + ""));
            });
        }

        // 返回差异列表
        return DiffVOs;
    }

    /**
     * 比较合同产品项目变更
     *
     * @param id 合同id
     * @return
     * @author 陈广煜
     * @date 2024-08-23
     */
    @Override
    public List<ProductDiffVO> getProductDiff(String id) {
        // 查询合同
        ContractAudit contractAudit = getEntity(id);
        // 查询上个版本合同
        ContractAudit lastContract = getLastContract(contractAudit);
        if (lastContract == null) {
            return null;
        }
        // 查询合同产品项目
        QueryWrapper<ContractProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ContractProduct::getContractAuditId, contractAudit.getId());
        List<ContractProduct> newestList = contractProductService.getEntityList(queryWrapper);
        List<ContractProductListVO> contractProductVOS = Binder.convertAndBindRelations(newestList, ContractProductListVO.class);
        queryWrapper.clear();
        queryWrapper.lambda().eq(ContractProduct::getContractAuditId, lastContract.getId());
        List<ContractProduct> lastList = contractProductService.getEntityList(queryWrapper);
        return compareProductLists(lastList, contractProductVOS);
    }

    @Override
    public List<ProductDiffVO> getCncProductDiff(String id) {
        // 查询合同
        ContractAudit contractAudit = getEntity(id);
        // 查询上个版本合同
        ContractAudit lastContract = getLastContract(contractAudit);
        if (lastContract == null) {
            return null;
        }
        // 查询合同产品项目
        QueryWrapper<ContractProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ContractProduct::getContractAuditId, contractAudit.getId());
        List<ContractProduct> newestList = contractProductService.getEntityList(queryWrapper);
        List<ContractProductListVO> contractProductVOS = Binder.convertAndBindRelations(newestList, ContractProductListVO.class);
        queryWrapper.clear();
        queryWrapper.lambda().eq(ContractProduct::getContractAuditId, lastContract.getId());
        List<ContractProduct> lastList = contractProductService.getEntityList(queryWrapper);
        return compareCncProductLists(lastList, contractProductVOS);
    }

    private static List<ProductDiffVO> compareCncProductLists(List<ContractProduct> oldList, List<ContractProductListVO> newList) {
        // 将旧产品列表转换为字典，以便快速查找
        Map<String, ContractProduct> oldMap = new HashMap<>();
        for (ContractProduct contractProduct : oldList) {
            oldMap.put(contractProduct.getSheetNum(), contractProduct);
        }
        // 将新产品列表转换为字典，以便快速查找
        Map<String, ContractProduct> newMap = new HashMap<>();
        for (ContractProductListVO contractProductListVO : newList) {
            newMap.put(contractProductListVO.getSheetNum(), contractProductListVO);
        }
        // 找出新旧产品列表中的共同产品
        Set<String> commonProducts = new HashSet<>(oldMap.keySet());
        commonProducts.retainAll(newMap.keySet());
        // 找出新增的产品
        Set<String> addedProducts = new HashSet<>(newMap.keySet());
        addedProducts.removeAll(oldMap.keySet());
        // 找出移除的产品
        Set<String> removedProducts = new HashSet<>(oldMap.keySet());
        removedProducts.removeAll(newMap.keySet());

        // 初始化差异列表
        List<ProductDiffVO> diffs = new ArrayList<>();

        // 处理新增的产品
        for (String productKey : addedProducts) {
            ContractProduct newProduct = newMap.get(productKey);
            String productType = newProduct.getProductType();
            diffs.add(new ProductDiffVO(
                    newProduct.getMachineType(),
                    productType,
                    null,
                    null,
                    null,
                    null,
                    newProduct.getProductDiscount(),
                    newProduct.getProductPrice(),
                    newProduct.getProductCount(),
                    newProduct.getContractPrice()
            ));
        }
        // 处理移除的产品
        for (String productKey : removedProducts) {
            ContractProduct oldProduct = oldMap.get(productKey);
            String productType = oldProduct.getProductType();
            diffs.add(new ProductDiffVO(
                    oldProduct.getMachineType(),
                    productType,
                    oldProduct.getProductDiscount(),
                    oldProduct.getProductPrice(),
                    oldProduct.getProductCount(),
                    oldProduct.getContractPrice(),
                    null,
                    null,
                    null,
                    null
            ));
        }
        // 处理共同的产品，找出发生变化的
        for (String productKey : commonProducts) {
            ContractProduct oldProduct = oldMap.get(productKey);
            ContractProduct newProduct = newMap.get(productKey);
            String productType = oldProduct.getProductType();

            if (!Objects.equals(oldProduct.getProductDiscount(), newProduct.getProductDiscount()) ||
                    !NumberUtil.equals(oldProduct.getProductPrice(), newProduct.getProductPrice()) ||
                    !Objects.equals(oldProduct.getProductCount(), newProduct.getProductCount()) ||
                    !NumberUtil.equals(oldProduct.getContractPrice(), newProduct.getContractPrice())) {
                diffs.add(new ProductDiffVO(
                        newProduct.getMachineType(),
                        productType,
                        oldProduct.getProductDiscount(),
                        oldProduct.getProductPrice(),
                        oldProduct.getProductCount(),
                        oldProduct.getContractPrice(),
                        newProduct.getProductDiscount(),
                        newProduct.getProductPrice(),
                        newProduct.getProductCount(),
                        newProduct.getContractPrice()));
            }
        }
        return diffs;
    }

    /**
     * 比较合同产品项目变更
     *
     * @param id
     * @param newList
     * @return
     * @author 陈广煜
     * @date 2024-08-23
     */
    @Override
    public List<ProductDiffVO> getProductDiff(String id, List<ContractProductListVO> newList) {
        QueryWrapper<ContractProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ContractProduct::getContractAuditId, id);
        List<ContractProduct> oldList = contractProductService.getEntityList(queryWrapper);
        return compareProductLists(oldList, newList);
    }

    /**
     * 查询上个版本合同
     *
     * @param contractAudit
     * @return
     * @author 陈广煜
     * @date 2024-08-23
     */
    private ContractAudit getLastContract(ContractAudit contractAudit) {
        if (contractAudit.getContractVersion() > 1) {
            QueryWrapper<ContractAudit> qw = new QueryWrapper<>();
            qw.eq("contract_code", contractAudit.getContractCode());
            qw.eq("contract_version", contractAudit.getContractVersion() - 1);
            return getSingleEntity(qw);
        }
        return null;
    }

    /**
     * 比较合同产品项目
     *
     * @param oldList 旧
     * @param newList 新
     * @return
     * @author 陈广煜
     * @date 2024-08-23
     */
    private List<ProductDiffVO> compareProductLists(List<ContractProduct> oldList, List<ContractProductListVO> newList) {
        IamTenant tenant = iamTenantService.getEntity(IamSecurityUtils.getCurrentTenantId());
        // 将旧产品列表转换为字典，以便快速查找
        Map<String, ContractProduct> oldMap = new HashMap<>();
        for (ContractProduct contractProduct : oldList) {
            if (S.equals(tenant.getCode(), "skxt")) {
                oldMap.put(contractProduct.getSheetNum(), contractProduct);
            } else {
                oldMap.put(contractProduct.getProductCode(), contractProduct);
            }
        }
        // 将新产品列表转换为字典，以便快速查找
        Map<String, ContractProduct> newMap = new HashMap<>();
        for (ContractProductListVO contractProductListVO : newList) {
            if (S.equals(tenant.getCode(), "skxt")) {
                newMap.put(contractProductListVO.getSheetNum(), contractProductListVO);
            } else {
                newMap.put(contractProductListVO.getProductCode(), contractProductListVO);
            }
        }
        // 找出新旧产品列表中的共同产品
        Set<String> commonProducts = new HashSet<>(oldMap.keySet());
        commonProducts.retainAll(newMap.keySet());
        // 找出新增的产品
        Set<String> addedProducts = new HashSet<>(newMap.keySet());
        addedProducts.removeAll(oldMap.keySet());
        // 找出移除的产品
        Set<String> removedProducts = new HashSet<>(oldMap.keySet());
        removedProducts.removeAll(newMap.keySet());

        // 初始化差异列表
        List<ProductDiffVO> diffs = new ArrayList<>();

        // 处理新增的产品
        for (String productKey : addedProducts) {
            ContractProduct newProduct = newMap.get(productKey);
            String productType = newProduct.getProductType();
            diffs.add(new ProductDiffVO(
                    productKey,
                    productType,
                    null,
                    null,
                    null,
                    null,
                    newProduct.getProductDiscount(),
                    newProduct.getProductPrice(),
                    newProduct.getProductCount(),
                    newProduct.getContractPrice()
            ));
        }
        // 处理移除的产品
        for (String productKey : removedProducts) {
            ContractProduct oldProduct = oldMap.get(productKey);
            String productType = oldProduct.getProductType();
            diffs.add(new ProductDiffVO(
                    productKey,
                    productType,
                    oldProduct.getProductDiscount(),
                    oldProduct.getProductPrice(),
                    oldProduct.getProductCount(),
                    oldProduct.getContractPrice(),
                    null,
                    null,
                    null,
                    null
            ));
        }
        // 处理共同的产品，找出发生变化的
        for (String productKey : commonProducts) {
            ContractProduct oldProduct = oldMap.get(productKey);
            ContractProduct newProduct = newMap.get(productKey);
            String productType = oldProduct.getProductType();

            if (!Objects.equals(oldProduct.getProductDiscount(), newProduct.getProductDiscount()) ||
                    !NumberUtil.equals(oldProduct.getProductPrice(), newProduct.getProductPrice()) ||
                    !Objects.equals(oldProduct.getProductCount(), newProduct.getProductCount()) ||
                    !NumberUtil.equals(oldProduct.getContractPrice(), newProduct.getContractPrice())) {
                diffs.add(new ProductDiffVO(
                        productKey,
                        productType,
                        oldProduct.getProductDiscount(),
                        oldProduct.getProductPrice(),
                        oldProduct.getProductCount(),
                        oldProduct.getContractPrice(),
                        newProduct.getProductDiscount(),
                        newProduct.getProductPrice(),
                        newProduct.getProductCount(),
                        newProduct.getContractPrice()));
            }
        }
        return diffs;
    }

    /**
     * 查询合同
     *
     * @param dto
     * @param type       草稿/正式
     * @param permission self/sub/all/star
     * @param pagination 分页
     * @return
     * @author 陈广煜
     * @date 2024-09-18
     */
    public JsonResult<List<ContractAuditVO>> selectContract(ContractAuditDTO dto, String type, String permission, Pagination pagination) {
        if (S.isBlank(pagination.getOrderBy())) {
            pagination.setOrderBy(Pagination.ORDER_BY_ID_DESC);
        }
        QueryWrapper<ContractAudit> queryWrapper = QueryBuilder.toQueryWrapper(dto, pagination);
        if (S.equals(type, "draft")) { // 草稿
            queryWrapper.lambda().and(ew -> ew.eq(ContractAudit::getContractStatus, ContractAuditStatusEnum.NO_SUBMIT.getCode())
                    .eq(ContractAudit::getAuditType, "create")
                    .and(w ->
                            w.eq(ContractAudit::getSigner, IamSecurityUtils.getCurrentUserId())
                                    .or()
                                    .eq(ContractAudit::getCreateBy, IamSecurityUtils.getCurrentUserId())));
        } else if (S.equals(type, "formal")) { // 正式
            queryWrapper.lambda().and(ew -> ew.ne(ContractAudit::getContractStatus, ContractAuditStatusEnum.NO_SUBMIT.getCode()).and(q -> {
                q.ne(ContractAudit::getContractStatus, ContractAuditStatusEnum.HISTORY.getCode()).ne(ContractAudit::getContractStatus, ContractAuditStatusEnum.ARCHIVED.getCode());
            }));
        }
        // 跨租户不做权限控制
        if (commonService.isCrossTenant(IamSecurityUtils.getCurrentTenantId())) {
            List<ContractAuditVO> viewObjectList = getViewObjectList(queryWrapper, pagination, ContractAuditVO.class);
            return JsonResult.OK(viewObjectList).bindPagination(pagination);
        }
        // 我的
        if (S.equals(permission, "self")) {
            queryWrapper.lambda().and(w ->
                    w.eq(ContractAudit::getSigner, IamSecurityUtils.getCurrentUserId())
                            .or()
                            .eq(ContractAudit::getCreateBy, IamSecurityUtils.getCurrentUserId())
                            .or()
                            .in(ContractAudit::getId, contractTeamService.getTeamContract(Collections.singletonList(IamSecurityUtils.getCurrentUserId()))));
        }
        // 下属
        if (S.equals(permission, "sub")) {
            List<String> subEmp = commonService.findSubEmp(IamSecurityUtils.getCurrentUser());
            if (subEmp.isEmpty()) {
                return JsonResult.OK(new ArrayList<>());
            }
            queryWrapper.lambda().and(ew -> ew.in(ContractAudit::getSigner, subEmp)
                    .or().in(ContractAudit::getId, contractTeamService.getTeamContract(subEmp)));
        }
        // 全部
        if (S.equals(permission, "all")) {
            List<String> subEmp = commonService.findSubEmp(IamSecurityUtils.getCurrentUser());
            subEmp.add(IamSecurityUtils.getCurrentUserId());
            queryWrapper.lambda().and(w -> {
                w.in(ContractAudit::getSigner, subEmp).or().eq(ContractAudit::getCreateBy, IamSecurityUtils.getCurrentUserId());
                List<String> teamContract = contractTeamService.getTeamContract(subEmp);
                if (!teamContract.isEmpty()) {
                    w.or().in(ContractAudit::getId, teamContract);
                }
            });
        }
        // 关注
        if (S.equals(permission, "star")) {
            List<String> starContractIds = contractAuditMapper.getStarContractIds(IamSecurityUtils.getCurrentUserId());
            if (starContractIds.isEmpty()) {
                return JsonResult.OK(new ArrayList<>());
            }
            queryWrapper.lambda().and(w -> w.in(ContractAudit::getId, starContractIds));
        }
        queryWrapper.orderBy(true, false, "id");
        List<ContractAuditVO> viewObjectList = getViewObjectList(queryWrapper, pagination, ContractAuditVO.class);
        viewObjectList.forEach(e -> {
            if (e.getStarUids() == null) {
                e.setStarUids(new ArrayList<>());
            }
            e.setIsStar(e.getStarUids().contains(IamSecurityUtils.getCurrentUserId()));
        });
        return JsonResult.OK(viewObjectList).bindPagination(pagination);
    }


    /**
     * 归档合同取消
     *
     * @param contractAuditIds 合同id
     */
    @Override
    public void cancelArchive(List<String> contractAuditIds) {
        UpdateWrapper<ContractAudit> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(ContractAudit::getContractStatus, ContractAuditStatusEnum.OA_SUCCESS.getCode()).in(ContractAudit::getId, contractAuditIds);
        update(updateWrapper);
    }

    /**
     * 接收OA回传
     *
     * @param objectid 对象ID
     * @param result   结果
     * @param bdcode   业务代码
     * @return JsonResult<String> 返回Json结果
     * @throws JCoException JCo异常
     */
    @Override
    public JsonResult<String> receiveOaApprovalAuditResults(String objectid, String result, String bdcode) throws JCoException {
        // 设置忽略拦截器
        ThreadLocalHolder.setIgnoreInterceptor();
        // 获取合同审核实体
        ContractAudit contractAudit = this.getEntity(objectid);
        // 如果合同审核实体为空
        if (contractAudit == null) {
            // 创建一个新的JsonResult对象
            JsonResult<String> jsonResult = new JsonResult<>();
            // 设置状态码为500
            jsonResult.setCode(500);
            // 设置消息为"合同不存在"
            jsonResult.setMsg("合同不存在");
            // 返回JsonResult对象
            return jsonResult;
        }
        // 设置业务代码为合同审核的审核类型
        bdcode = contractAudit.getAuditType();
        // 如果业务代码为"update"
        if (S.contains(bdcode, ContractAuditTypeEnum.UPDATE.getCode())) {
            // 设置忽略拦截器
            ThreadLocalHolder.setIgnoreInterceptor();
            // 创建一个更新包装器
            UpdateWrapper<ContractAuditUpdate> updateWrapper = new UpdateWrapper<>();
            // 设置更新条件
            updateWrapper.lambda()
                    // 设置OA状态
                    .set(ContractAuditUpdate::getOaStatus, result)
                    // 根据合同审核ID进行更新
                    .eq(ContractAuditUpdate::getContractAuditId, objectid);
            // 更新合同审核更新实体
            contractAuditUpdateService.updateEntity(updateWrapper);
        }
        // 如果业务代码为"cancel"
        if (S.contains(bdcode, ContractAuditTypeEnum.CANCEL.getCode())) {
            log.info("合同取消");
            // 设置忽略拦截器
            ThreadLocalHolder.setIgnoreInterceptor();
            // 创建一个更新包装器
            UpdateWrapper<ContractAuditCancel> updateWrapper = new UpdateWrapper<>();
            // 设置更新条件
            updateWrapper.lambda()
                    // 设置OA状态
                    .set(ContractAuditCancel::getOaStatus, result)
                    // 根据合同审核ID进行更新
                    .eq(ContractAuditCancel::getContractAuditId, objectid);
            // 更新合同审核取消实体
            contractAuditCancelService.updateEntity(updateWrapper);
            // 如果OA评审通过
            if (S.equals("已完成", result)) {
                // 创建一个查询包装器
                QueryWrapper<ContractProduct> productQueryWrapper = new QueryWrapper<>();
                // 设置查询条件
                productQueryWrapper.lambda().select(ContractProduct::getId)
                        // 根据合同审核ID进行查询
                        .eq(ContractProduct::getContractAuditId, contractAudit.getId());
                // 设置忽略拦截器
                ThreadLocalHolder.setIgnoreInterceptor();
                // 获取合同产品列表
                List<ContractProduct> contractProductList = contractProductService.getEntityList(productQueryWrapper);
                // 创建一个查询包装器
                QueryWrapper<SalesContract> salesContractQueryWrapper = new QueryWrapper<>();
                // 设置查询条件
                salesContractQueryWrapper.lambda().select(SalesContract::getId, SalesContract::getSapCode)
                        // 根据合同产品ID进行查询
                        .in(SalesContract::getContractProductId, contractProductList.stream()
                                .map(ContractProduct::getId)
                                .collect(Collectors.toList()));
                // 设置忽略拦截器
                ThreadLocalHolder.setIgnoreInterceptor();
                // 获取销售合同列表
                List<SalesContract> salesContracts = salesContractService.getEntityList(salesContractQueryWrapper);
                // 遍历销售合同列表
                for (SalesContract salesContract : salesContracts) {
                    // 如果销售合同的SAP代码不为空
                    if (S.isNotBlank(salesContract.getSapCode())) {
                        log.info("销售合同" + salesContract.getId() + "取消SAP合同");
                        // 取消SAP合同
                        salesContractService.cancelSap(salesContract.getId());
                    }
                }
            }
        }
        // 设置忽略拦截器
        ThreadLocalHolder.setIgnoreInterceptor();
        // 创建一个更新包装器
        UpdateWrapper<ContractAudit> updateWrapper = new UpdateWrapper<>();
        // 设置更新条件
        updateWrapper.lambda().set(ContractAudit::getOaMsg, result)
                // 设置OA状态
                .set(ContractAudit::getOaStatus, OAStatusEnum.RESP.getCode())
                // 设置合同状态
                .set(ContractAudit::getContractStatus, S.equals("已完成", result) ? S.contains(bdcode, ContractAuditTypeEnum.CANCEL.getCode()) ? ContractAuditStatusEnum.CANCEL.getCode() : ContractAuditStatusEnum.OA_SUCCESS.getCode() : ContractAuditStatusEnum.OA_FAIL.getCode())
                // 根据ID进行更新
                .eq(ContractAudit::getId, objectid);
        // 红外事业部合同 合同审批，合同变更通过后状态为补充技术清单
        if (S.equals("IPL", contractAudit.getBusinessModel()) && !bdcode.contains("cancel") && S.equals("已完成", result)) {
            updateWrapper.lambda().set(ContractAudit::getContractStatus, ContractAuditStatusEnum.SUPPLEMENTARY_TECHNOLOGY_LIST.getCode());
        }
        // 更新合同审核实体
        updateEntity(updateWrapper);
        // 创建一个新的JsonResult对象
        JsonResult<String> jsonResult = new JsonResult<>();
        // 设置状态码为200
        jsonResult.setCode(200);
        // 设置消息为"操作成功"
        jsonResult.setMsg("操作成功");
        // 返回JsonResult对象
        return jsonResult;
    }

    @Override
    public Map<String, String> getSapMrlDetail(String mrlCode, String salesOrg, String sapNo) {
        List<Konp> sapMrl = konpService.getSapMrl(sapNo, salesOrg, Collections.singletonList(mrlCode));
        if (sapMrl.isEmpty()) {
            sapMrl = konpService.getSapMrl(salesOrg, Collections.singletonList(mrlCode));
        }
        Map<String, String> result = new HashMap<>();
        if (sapMrl.isEmpty()) {
            return result;
        }
        result.put("desc", sapMrl.get(0).getMaktx());
        result.put("price", sapMrl.get(0).getKbetr());
        return result;
    }

    @Override
    public List<Map<String, String>> getSapMrlList(String mrlCode, String salesOrg, String sapNo, Pagination pagination) {
        Page<Konp> page = konpService.getSapMrlPage(sapNo, salesOrg, mrlCode, new Page(pagination.getPageIndex(), pagination.getPageSize()));
        if (page == null || page.getRecords().isEmpty()) {
            return Collections.emptyList();
        }
        List<Map<String, String>> list = new ArrayList<>();
        List<Konp> records = page.getRecords();
        for (int i = 0; i < records.size(); i++) {
            Konp konp = records.get(i);
            Map<String, String> map = new HashMap<>();
            map.put("desc", konp.getMaktx());
            map.put("price", konp.getKbetr());
            map.put("mrlCode", konp.getMatnr());
            map.put("customerCode", konp.getKunnr());
            map.put("salesOrg", konp.getVkorg());
            map.put("rowNum", i + 1 + "");
            list.add(map);
        }

        pagination.setTotalCount(page.getTotal());
        return list;
    }

    @Override
    public String printWord(String id) {
        // 获取合同审核详情
        ContractAuditVO detail = getViewObject(id, ContractAuditVO.class);
        if (detail.getIsAudit() && !S.equals(ContractAuditStatusEnum.OA_SUCCESS.getCode(), detail.getContractStatus())
                && !S.equals(ContractAuditStatusEnum.SUPPLEMENTARY_TECHNOLOGY_LIST.getCode(), detail.getContractStatus())
                && !S.equals(ContractAuditStatusEnum.DONE.getCode(), detail.getContractStatus())
                && !S.equals(ContractAuditStatusEnum.ARCHIVED.getCode(), detail.getContractStatus())
                && !S.equals(ContractAuditStatusEnum.CANCEL.getCode(), detail.getContractStatus())
        ) {
            throw new BusinessException("合同审批未通过");
        }
        String resourceFilePath = getResourceFilePath("word/sys-sam-contract-tl.docx");
//        String templateFilePath = getTemplateFilePath(detail.getContractCode(), "产品供销合同.docx");
        String tempDir = getTemplateFilePath() + detail.getContractCode() + "/";
        File td = new File(tempDir);
        if (!td.exists()) {
            td.mkdir();
        }
        String templateFilePath = tempDir + detail.getContractCode() + "产品供销合同.docx";
        // 模板数据
        Map<String, Object> params = new HashMap<>();
        ContractInfoListVO contractInfoVO = detail.getContractInfoVO();
        if (contractInfoVO != null) {
            contractInfoVO.setTotalAmount(contractInfoVO.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
            detail.setContractAmount(contractInfoVO.getTotalAmount().toString());
        }
        String jsonStr = fieldMappingService.entityToJson(detail, "sys-sam-contract");
        Map<Object, Object> map = JSON.toMap(jsonStr);
        for (Map.Entry<Object, Object> en : map.entrySet()) {
            params.put(en.getKey().toString(), Texts.of(en.getValue().toString()).create());
        }
        // 合同项目列表
        List<ContractProductListVO> plist = detail.getContractProductVOList();
        plist.forEach(item -> {
            if (item.getProductPrice() != null) {
                item.setProductPrice(item.getProductPrice().setScale(2, RoundingMode.HALF_UP));
            }
            if (item.getContractPrice() != null) {
                item.setContractPrice(item.getContractPrice().setScale(2, RoundingMode.HALF_UP));
            }
        });
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        Configure conf = Configure.builder().bind("productList", policy).build();
        params.put("productList", plist);
        try (XWPFTemplate template = XWPFTemplate.compile(resourceFilePath, conf).render(params); FileOutputStream fos = new FileOutputStream(templateFilePath)) {
            template.write(fos);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String techTempFilePath = getResourceFilePath("word/sys-sam-tech-tl.docx");
        String techTempFilePathWithAmount = getResourceFilePath("word/sys-sam-tech-with-amount-tl.docx");
        LoopRowTableRenderPolicy techPolicy = new LoopRowTableRenderPolicy();
        Configure techConf = Configure.builder().bind("tech", techPolicy).build();
        for (ContractProductListVO item : plist) {
            List<ContractProductMaterialVO> mrlList = item.getContractProductMaterialVOList();
            for (int i = 0; i < mrlList.size(); i++) {
                mrlList.get(i).setRowNumber(i + 1);
            }
            String tf = tempDir + detail.getContractCode() + "-" + item.getProductCode() + "技术清单(不带金额).docx";
            String tfWithAmount = tempDir + detail.getContractCode() + "-" + item.getProductCode() + "技术清单.docx";
            Map<String, Object> techParams = new HashMap<>();
            techParams.put("customerName", detail.getCustomerName());
            techParams.put("contractCode", detail.getContractCode());
            techParams.put("machineToolCode", item.getMachineType());
            techParams.put("count", item.getProductCount());
            techParams.put("tech", mrlList);
            try (XWPFTemplate techTemplate = XWPFTemplate.compile(techTempFilePath, techConf).render(techParams);
                 FileOutputStream techFos = new FileOutputStream(tf);
                 XWPFTemplate techTemplateWithAmount = XWPFTemplate.compile(techTempFilePathWithAmount, techConf).render(techParams);
                 FileOutputStream techFosWithAmount = new FileOutputStream(tfWithAmount);
            ) {
                techTemplate.write(techFos);
                techTemplateWithAmount.write(techFosWithAmount);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        // 压缩文件
        String dir = tempDir.substring(0, tempDir.lastIndexOf("/"));
        String zipPath = dir + ".zip";
        try (FileOutputStream zipOut = new FileOutputStream(zipPath);
             ZipOutputStream zipOutputStream = new ZipOutputStream(zipOut)) {
            WordUtils.addFolderToZip("", dir, zipOutputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 返回压缩文件路径
        return zipPath;
    }

    public String getResourceFilePath(String resourcePath) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream(resourcePath);
        if (resourceAsStream == null) {
            throw new RuntimeException("未找到模板文件");
        }
        String systemTempDir = FileHelper.getSystemTempDir().replaceAll("\\\\", "/");
        if (!systemTempDir.endsWith("/")) {
            systemTempDir += "/";
        }
        // 创建临时文件
        File tempFile = null;
        try {
            tempFile = new File(systemTempDir, System.currentTimeMillis() + resourcePath.substring(resourcePath.lastIndexOf("/") + 1));
            Files.copy(resourceAsStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            log.error("创建临时文件失败{}", e.getMessage());
            throw new RuntimeException("创建临时文件失败", e);
        }
        return tempFile.getPath();
    }

    public String getTemplateFilePath() {
        String systemTempDir = FileHelper.getSystemTempDir();
        if (!systemTempDir.endsWith("/")) {
            systemTempDir += "/";
        }
        systemTempDir += "crm-temp/";
        File tempDir = new File(systemTempDir);
        if (!tempDir.exists()) {
            tempDir.mkdir();
        }
        return systemTempDir;
    }

    /**
     * 添加技术清单
     *
     * @param contractProductListVO
     */
    @Override
    public void addTechList(ContractProductListVO contractProductListVO) {
        QueryWrapper<ContractProductMaterial> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ContractProductMaterial::getContractProductId, contractProductListVO.getId());
        // 删除已存在的物料
        contractProductMaterialService.deleteEntities(queryWrapper);
        List<ContractProductMaterialVO> contractProductMaterialVOList = contractProductListVO.getContractProductMaterialVOList();
        // 技术清单总金额
        BigDecimal totalPrice = BigDecimal.ZERO;
        for (ContractProductMaterialVO contractProductMaterialVO : contractProductMaterialVOList) {
            totalPrice = totalPrice.add(contractProductMaterialVO.getMaterialPrice().multiply(new BigDecimal(contractProductMaterialVO.getMaterialCount())));
        }
        // 合同金额
        BigDecimal contractAmount = contractProductListVO.getProductPrice().multiply(new BigDecimal(contractProductListVO.getProductCount()));
        // 计算折扣 合同金额/技术清单总金额
        BigDecimal discount = contractAmount.divide(totalPrice, 2, RoundingMode.HALF_UP);
        contractProductListVO.setProductDiscount(discount);
        contractProductMaterialVOList.forEach(e -> {
            e.setId(null);
            e.setActualDiscount(discount);
            e.setMaterialDiscount(discount);
            e.setContractProductId(contractProductListVO.getId());
        });
        contractProductService.updateEntity(contractProductListVO);
        contractProductMaterialService.createOrUpdateEntities(contractProductMaterialVOList);
    }

    @Override
    public Map<String, String> getSapInventory(List<ContractProductMaterial> mrlList) throws JCoException {
        if (mrlList == null || mrlList.size() == 0) {
            return null;
        }
        IamTenant tenant = iamTenantService.getEntity(IamSecurityUtils.getCurrentTenantId());
        List<LabelValue> companyCell = dictionaryService.getLabelValueList("companyCell");
        String str = companyCell.stream().filter(e -> e.getLabel().equals(tenant.getOaNum())).map(LabelValue::getValue).findFirst().orElse("").toString();
        return sapUtil.getSapInventory(mrlList, S.splitToList(str), tenant.getOaNum());
    }

    /**
     * 查询合同变更详情
     *
     * @return
     */
    @Override
    public JsonResult<List<ContractAuditUpdateListVO>> selectContractUpdateDetailList(List<ContractAuditUpdate> updates) {
        if (updates == null || updates.size() == 0) {
            return JsonResult.OK();
        }
        QueryWrapper<ContractAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(ContractAudit::getId, updates.stream().map(ContractAuditUpdate::getContractAuditId).collect(Collectors.toList())).orderByDesc(ContractAudit::getId);
        List<ContractAudit> contractAudits = this.getEntityList(queryWrapper);
        List<ContractAuditVO> contractAuditVOS = Binder.convertAndBindRelations(contractAudits, ContractAuditVO.class);
        for (ContractAuditVO contractAuditVO : contractAuditVOS) {
            ContractAuditUpdateListVO contractAuditUpdateVO = contractAuditVO.getContractAuditUpdateVO();
            contractAuditUpdateVO.setMachineModel(contractAuditVO.getContractInfoVO().getMachineToolCode());
            contractAuditUpdateVO.setCustomerName(contractAuditVO.getContractInfoVO().getCustomerName());
            contractAuditUpdateVO.setContractSignTime(contractAuditVO.getContractExtVO() == null ? contractAuditVO.getAuditTime() : contractAuditVO.getContractExtVO().getBuyerSignTime());
            contractAuditUpdateVO.setOrderModel(contractAuditVO.getContractProductVOList().stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "")).collect(Collectors.joining(";")));
            contractAuditUpdateVO.setSalesperson(contractAuditVO.getSalerName());
            String contractType = contractAuditVO.getContractTypeLabel() == null ? "" : contractAuditVO.getContractTypeLabel().getLabel();
            contractAuditUpdateVO.setContractType(contractType);
        }
        List<ContractAuditUpdateListVO> contractAuditUpdateListVOS = contractAuditVOS.stream().map(ContractAuditVO::getContractAuditUpdateVO).toList();
        return JsonResult.OK(contractAuditUpdateListVOS);
    }

    @Override
    public JsonResult<List<ContractAuditCancelListVO>> selectContractCancelDetailList(List<ContractAuditCancel> cancels) {
        if (cancels == null || cancels.size() == 0) {
            return JsonResult.OK();
        }
        QueryWrapper<ContractAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(ContractAudit::getId, cancels.stream().map(ContractAuditCancel::getContractAuditId).collect(Collectors.toList())).orderByDesc(ContractAudit::getId);
        List<ContractAudit> contractAudits = this.getEntityList(queryWrapper);
        List<ContractAuditVO> contractAuditVOS = Binder.convertAndBindRelations(contractAudits, ContractAuditVO.class);
        for (ContractAuditVO contractAuditVO : contractAuditVOS) {
            ContractAuditCancelListVO cancelVO = contractAuditVO.getContractAuditCancelVO();
            cancelVO.setContractAmount(contractAuditVO.getContractInfoVO().getTotalAmount().toString());
            cancelVO.setContractSignTime(contractAuditVO.getContractExtVO() == null ? contractAuditVO.getAuditTime() : contractAuditVO.getContractExtVO().getBuyerSignTime());
            cancelVO.setSalesPerson(contractAuditVO.getSalerName());
            String customerType = contractAuditVO.getCustomerTypeLabel() == null ? "" : contractAuditVO.getCustomerTypeLabel().getLabel();
            cancelVO.setCustomerNature(customerType);
            cancelVO.setCustomerName(contractAuditVO.getCustomerName());
            cancelVO.setMachineModel(contractAuditVO.getContractProductVOList().stream().map(e -> StrUtil.nullToDefault(e.getMachineType(), "") + "/" + StrUtil.nullToDefault(e.getMachineType(), "")).collect(Collectors.joining(";")));
            String discount = contractAuditVO.getContractProductVOList().stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "") + ":" + e.getProductDiscount()).collect(Collectors.joining(";"));
            String orderModel = contractAuditVO.getContractProductVOList().stream().map(e -> StrUtil.nullToDefault(e.getProductCode(), "") + "/" + StrUtil.nullToDefault(e.getProductType(), "")).collect(Collectors.joining(";"));
            cancelVO.setContractDiscount(discount);
            cancelVO.setOrderModel(orderModel);
            cancelVO.setContractNum(String.valueOf(contractAuditVO.getContractProductVOList().size()));
        }
        List<ContractAuditCancelListVO> contractAuditUpdateListVOS = contractAuditVOS.stream().map(ContractAuditVO::getContractAuditCancelVO).toList();
        return JsonResult.OK(contractAuditUpdateListVOS);
    }

    /**
     * 批量更新合同产品的SAP合同推送状态
     *
     * @param ids 需要更新状态的合同产品ID列表，传入null或空列表时将直接返回不执行操作
     * @return 无返回值
     */
    @Override
    public void updateSapStatus(List<String> ids) {
        // 参数有效性校验：当传入空列表时提前返回
        if (ids == null || ids.size() == 0) {
            return;
        }
        UpdateWrapper<ContractProduct> qw = new UpdateWrapper<>();
        qw.lambda()
                .set(ContractProduct::getSapContractPushStatus, 1)  // 设置状态字段值为1
                .in(ContractProduct::getId, ids);                   // 添加ID列表过滤条件
        // 执行批量更新操作
        contractProductService.updateEntity(qw);
    }

}